package cn.itcast.web.controller;

import cn.itcast.domain.system.Module;
import cn.itcast.domain.system.User;
import cn.itcast.service.system.ModuleService;
import cn.itcast.service.system.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.List;
import java.util.Random;

@Controller
public class LoginController extends  BaseController {

    @Autowired
    private UserService userService;

    @Autowired
    private ModuleService moduleService;
    //随机变量
    private Random random = new Random();

    /*
        作用：用户登陆
        url: /login.do
        参数： email,password
     */
    @RequestMapping("/login")
    public String login(String email,String password,String vcode){
        System.out.println("输入的验证码是"+vcode);
        String code = (String) request.getSession().getAttribute("code");
        System.out.println("生成的验证码是"+code);
        //1. 判断邮箱与密码是否为空，如果为空则跳回到登录页面
        if(StringUtils.isEmpty(email)|| StringUtils.isEmpty(password)){
            request.setAttribute("error","用户名或者密码不能为空!");
            //如果返回值不需要经过视图解析器，需要使用redirect或者forward开头
            return "forward:/login.jsp";
        }

        try {
            //2. 得到subject对象
            Subject subject = SecurityUtils.getSubject();
            //3. 把邮箱与密码封装到一个Token
            UsernamePasswordToken token = new UsernamePasswordToken(email,password);

            //4. subject发出认证请求
            subject.login(token);

            //5.登录成功会 返回一个登陆成功对象,shiro在你登陆成功之后会往session中做登陆成功标记
            User loginUser = (User) subject.getPrincipal();
            //这里的session的数据只是为了让我们方便使用登陆者的信息而已，并不是登录成功标记
            session.setAttribute("loginUser",loginUser);
            //一旦该用户登陆成功之后，马上就应该查找该用户对应的权限
            List<Module> moduleList = moduleService.findModuleByUser(loginUser);
            session.setAttribute("modules",moduleList);
            return "home/main";
        } catch (UnknownAccountException e) {
           //如果用户名不存在则抛出UnknownAccountException
            request.setAttribute("error","用户名不存在或者密码错误!");
            return "forward:/login.jsp";
        }catch (IncorrectCredentialsException e){
            //如果用户名不存在则抛出UnknownAccountException
            request.setAttribute("error","用户名不存在或者密码错误!");
            return "forward:/login.jsp";
        }
    }


    /*
          作用：用户注销

          注销的方案：
            1. 把session的登陆成功标记删除 session.removeAttribute("loginUser")
            2. 摧毁整个session
    */
    @RequestMapping("/logout")
    public String logout(){
        //1. 销毁shiro登陆成功标记
        Subject subject = SecurityUtils.getSubject();
        subject.logout(); //这个方法的作用销毁shiro登陆成功标记
        session.invalidate();
        //请求重定向: 会报错的   请求转发是没问题
        return "redirect:/login.jsp";  //请求重定向的时候会经过shiro的过滤器，shiro的过滤器由于不知道你已经是注销了，所以shiro的过滤器还是从session中获取登陆的标记信息
    }

    /*
       作用：加载home/home页面进内容区域
    */
    @RequestMapping("/home")
    public String home(){
        return "home/home";
    }

    /*
           作用：
           路径：
           参数：
           返回值：
       */
    @RequestMapping("/CheckCodeServlet")
    @ResponseBody
    public boolean CheckCodeServlet() throws IOException {
        /*
         * 目标: 使用java的awt包创建图片并在图片上画验证码,最后浏览器输出图片
         * */

        //1.创建缓存图片
        //语法：new BufferedImage(int width,int height,int rgb);
        //      创建图片设置图片宽度，高度，图片模式
        BufferedImage image = new BufferedImage(150,50,BufferedImage.TYPE_INT_RGB);

        //2.获取画笔对象
        Graphics g = image.getGraphics();

        //3.画画
        //设置画笔的颜色(白色)
        g.setColor(Color.white);

        //填充一个矩形画图区域
        //语法：g.fillRect(int x,int y,int width,int height);
        //     设置一个起始点（x轴和y轴），width矩形宽度，height矩形的高度
        g.fillRect(0,0,150,50);

        //画边框线,设置画笔颜色为黑色
        g.setColor(Color.black);
        //语法：g.drawRect(int x,int y,int width,int height);
        //     设置一个起始点（x轴和y轴），width矩形宽度，height矩形的高度
        g.drawRect(1,1,147,47);

        //画干扰线(4条线)
        //语法：g.drawLine(int x1,int y1,int x2,int y2);
        //     设置2个点的位置画一条线
        for (int i = 0; i < 4; i++) {
            //设置画笔随机颜色
            g.setColor(getRandomColor());

            int x1 = random.nextInt(147);
            int y1 = random.nextInt(47);
            int x2 = random.nextInt(147);
            int y2 = random.nextInt(47);
            g.drawLine(x1,y1,x2,y2);
        }

        //画随机4个字符的验证码到图片上
        //确定验证码字符的范围
        String str = "0123456789";
        //定义变量拼接4个随机获取的字符
        StringBuilder checkCodeBuilder = new StringBuilder();
        for (int i = 0; i < 4; i++) {

            //获取一个随机的位置
            int index = random.nextInt(str.length());

            //根据位置获取对应的字符
            char c = str.charAt(index);

            //拼接上到变量中
            checkCodeBuilder.append(c);

            //设置字体
            g.setFont(new Font("微软雅黑",Font.BOLD,20));

            //将这个字符画到图片上
            //语法：g.drawString(String str,int x,int y);
            //     将指定的字符串画到指定图片的位置上
            g.drawString(c+"",i*30+30,30);
        }

        //将生产的验证码字符串存储到会话域中
        request.getSession().setAttribute("code",checkCodeBuilder.toString());

        //4.输出图片到浏览器上
        //语法：ImageIO.write(内存图片对象,图片格式,response输出流)
        ImageIO.write(image,"png",response.getOutputStream());

        return true;
    }

    /**
     * 获取随机颜色对象
     * @return Color
     */
    private Color getRandomColor(){

        //创建Color对象的语法: new Color(int r,int g,int b);
        // rgb,每个值的有效范围是0~255
        int r = random.nextInt(256);
        int g = random.nextInt(256);
        int b = random.nextInt(256);
        return  new Color(r,g,b);
    }
}
